---
title: "Support for strategic voting campaigns: Evidence from a survey experiment during the German General Election of 2021 (R Script)"
author: "Michael Jankowski, michael.jankowski@uol.de"
date: "December 2022"
output:
  rmdformats::robobook:
    use_bookdown: true
    self_contained: true
    thumbnails: false
    lightbox: true
    gallery: false
    highlight: tango
editor_options:
  chunk_output_type: console
---

# About

This script shows how to replicate the figures and tables included in the paper "Support for strategic voting campaigns: Evidence from a survey experiment during the German General Election of 2021" published in the PVS. If you have any questions, please contact me via michael.jankowski\@uol.de or visit my webpage: <https://michael-jankowski.de/>

# Install Packages

This notebook describes the replication of the article: "Support for strategic voting campaigns: Evidence from a survey experiment during the German General Election of 2021" published in the *Politische Vierteljahresschrift*. The first step is to install all required packages.

```{r pkgs}
# Check if all required packages are installed

pkgs <- c("tidyverse",
          "margins",
          "cowplot",
          "Zelig",
          "xtable",
          "visreg",
          "pander",
          "readxl")

install_load <- function(packages){
  
  for (p in packages) {
    
    if (p %in% rownames(installed.packages())) {
      
      library(p, character.only=TRUE)
      
    } else {
      
      install.packages(p)
      library(p,character.only = TRUE)
      
    }
  }
}

install_load(pkgs)
```

# Load Data

The required data can be loaded via:

```{r data}
df <- readRDS("final_maassen.rds")
```

# Table 1

The following code creates Table 1 (descriptive statistics).

```{r, results = 'asis'}
df$control <- as.numeric(df$maassen_treatment == "Base")
df$Info <- as.numeric(df$maassen_treatment == "Information")
df$Cue <- as.numeric(df$maassen_treatment == "Party Cue")
df$Both <- as.numeric(df$maassen_treatment == "Both")

desc_stat <- function(x) {
  y <- df[[x]]
  
  miny <- min(y)
  maxy <- max(y)
  quanty <- quantile(y, probs = c(0.25, 0.5, 0.75))
  meany <- mean(y)
  mediany <- quanty[2]
  two5y <- quanty[1]
  seven5y <- quanty[3]
  
  data.frame(var = x,
             meany,
             two5y,
             mediany,
             seven5y,
             miny,
             maxy)
  
  
}

ds <- map_df(
  c(
    "maassen_outcome",
    "control",
    "Info",
    "Cue",
    "Both",
    "leftright",
    "vote2017_green",
    "partyeval_6",
    "pint",
    "abi",
    "gender",
    "age"
  ),
  desc_stat
)

names(ds) <- c("Variable",
               "Mean",
               "1st Q.",
               "Median",
               "3rd Q.",
               "Min.",
               "Max.")

ds %>%
  xtable::xtable(digits = 2) %>%
  xtable::print.xtable(bookstabs = TRUE,
                       type = "html",
                       include.rownames = FALSE)
```

# Figure 1

The following code creates Figure 1 (bar plot of the dependent variable).

```{r,fig.width=10,fig.height=4}
df %>%
  group_by(maassen_outcome) %>%
  count() %>%
  ungroup() %>%
  mutate(perc = round(100 * n / sum(n), 1)) %>%
  ggplot(aes(x = maassen_outcome,
             y = perc,
             fill = maassen_outcome)) +
  geom_col(color = "black") +
  scale_x_continuous(breaks = 1:10,
                     labels = c("1\n(very bad)",
                                2:9,
                                "10\n(very good)")) +
  geom_vline(aes(xintercept = mean(df$maassen_outcome)),
             lty = 2,
             color = "black",
             size = 1) +
  theme_bw(base_size = 14) +
  ylab("% of Responses") +
  xlab("Evaluation of Campaign") +
  theme(panel.grid.major = element_blank(),
        panel.grid.minor = element_blank()) +
  guides(fill = "none") +
  scale_fill_gradient2(
    low = "darkred",
    mid = "grey90",
    high = "darkgreen",
    midpoint = 5.5
  )

ggsave(file = "Figure1.pdf",
       width = 10,
       height = 6)
```

# Regression Models

The following code runs the OLS regression models 1 and 2.

```{r}
ols <- lm(maassen_outcome ~ info_treatment * party_treatment,
          data = df)

ols2 <- lm(
  maassen_outcome ~ info_treatment * party_treatment +
    leftright +
    gender +
    age +
    vote2017_green +
    pint +
    abi +
    partyeval_6,
  data = df
)
```

## Marginal Effect Plots (Figure 2)

The following code creates Figure 2.

```{r, fig.width=10,fig.height=4,message=F,warning=F}
margins(ols,
        variables = "info_treatment",
        at = list("party_treatment" = 0:1)) %>%
  summary %>% as.data.frame -> info_cond

margins(ols,
        variables = "party_treatment",
        at = list("info_treatment" = 0:1)) %>%
  summary %>% as.data.frame -> party_cond

ggplot(info_cond, aes(
  x = ifelse(party_treatment == 0, "No", "Yes"),
  y = AME,
  ymin = lower,
  ymax = upper
)) +
  geom_hline(aes(yintercept = 0), lty = 2) +
  geom_pointrange() +
  coord_flip() +
  theme_bw(base_size = 14) +
  ylab("AME(Information Treatment)") +
  xlab("Party Cue\nTreatment") +
  theme(panel.grid.major = element_blank(),
        panel.grid.minor = element_blank()) +
  lims(y = c(-0.6, 1.3)) -> info_plot

ggplot(party_cond, aes(
  x = ifelse(info_treatment == 0, "No", "Yes"),
  y = AME,
  ymin = lower,
  ymax = upper
)) +
  geom_hline(aes(yintercept = 0), lty = 2) +
  geom_pointrange() +
  coord_flip() +
  theme_bw(base_size = 14) +
  ylab("AME(Party Cue Treatment)") +
  xlab("Information\nTreatment") +
  theme(panel.grid.major = element_blank(),
        panel.grid.minor = element_blank()) +
  lims(y = c(-0.6, 1.3)) -> party_plot

plot_grid(info_plot,
          party_plot,
          labels = c("A", "B")) -> combo_plot

combo_plot

ggsave(combo_plot,
       file = "Figure2.pdf",
       width = 10,
       height = 4)
```

## Marginal Effect Plots - (Appendix Figure)

The following code creates the marginal effect plot from the appendix.

```{r, fig.width=10,fig.height=4}
margins(ols2,
        variables = "info_treatment",
        at = list("party_treatment" = 0:1)) %>%
  summary %>% as.data.frame -> info_cond2

margins(ols2,
        variables = "party_treatment",
        at = list("info_treatment" = 0:1)) %>%
  summary %>% as.data.frame -> party_cond2

ggplot(info_cond2, aes(
  x = ifelse(party_treatment == 0, "No", "Yes"),
  y = AME,
  ymin = lower,
  ymax = upper
)) +
  geom_hline(aes(yintercept = 0), lty = 2) +
  geom_pointrange() +
  coord_flip() +
  theme_bw(base_size = 14) +
  ylab("AME(Information Treatment)") +
  xlab("Party Cue\nTreatment") +
  theme(panel.grid.major = element_blank(),
        panel.grid.minor = element_blank()) +
  lims(y = c(-0.6, 1.3)) -> info_plot2

ggplot(party_cond2, aes(
  x = ifelse(info_treatment == 0, "No", "Yes"),
  y = AME,
  ymin = lower,
  ymax = upper
)) +
  geom_hline(aes(yintercept = 0), lty = 2) +
  geom_pointrange() +
  coord_flip() +
  theme_bw(base_size = 14) +
  ylab("AME(Party Cue Treatment)") +
  xlab("Information\nTreatment") +
  theme(panel.grid.major = element_blank(),
        panel.grid.minor = element_blank()) +
  lims(y = c(-0.6, 1.3)) -> party_plot2

plot_grid(info_plot2,
          party_plot2,
          labels = c("A", "B")) -> combo_plot2

combo_plot2

ggsave(combo_plot2,
       file = "Figure2appendix.pdf",
       width = 10,
       height = 4)
```

## OLS Regression Table (Table 2)

The following code creates the regression table.

```{r,results='asis'}
texreg::htmlreg(
  list(ols, ols2),
  stars = c(0.1, 0.05, 0.01, 0.001),
  booktabs = TRUE
)
```

## Effect Size Comparison (Figure 3)

The following code creates Figure 3.

```{r,fig.width=10,fig.height=6,message=F,warning=F}
sim_fd <- function(x, nsim = 5000) {
  dfx <- df
  
  dfx$indep <- dfx[[x]]
  
  ols_form <- paste0(
    "maassen_outcome ~ info_treatment +
  party_treatment +
  info_treatment*party_treatment +
  leftright +
  gender +
  age +
  vote2017_green +
  pint +
  abi +
  partyeval_6"
  )
  
  ols_form <- gsub(x, "indep", ols_form)
  
  ols_zelig <- zelig(
    as.formula(ols_form),
    data = dfx,
    model = "ls",
    cite = F
  )
  
  quant1 <-
    as.numeric(quantile(dfx$indep,
                        na.rm = TRUE,
                        probs = 0.25))
  quant3 <-
    as.numeric(quantile(dfx$indep,
                        na.rm = TRUE,
                        probs = 0.75))
  
  q1 <- setx(ols_zelig, indep = quant1)
  
  q3 <- setx(ols_zelig, indep = quant3)
  
  
  s.out <- Zelig::sim(ols_zelig,
                      x = q1,
                      x1 = q3,
                      num = nsim)
  
  fd.med <- median(s.out$sim.out$x1$fd[[1]])
  fd.lo <- quantile(s.out$sim.out$x1$fd[[1]], prob = 0.025)
  fd.up <- quantile(s.out$sim.out$x1$fd[[1]], prob = 0.975)
  
  data.frame(
    med = fd.med,
    lower = fd.lo,
    upper = fd.up,
    var = x
  )
  
}

fds <- map_df(
  c(
    "info_treatment",
    "party_treatment",
    "leftright",
    "vote2017_green",
    "partyeval_6",
    "pint",
    "abi",
    "gender",
    "age"
  ),
  sim_fd
)

clean_names <- data.frame(
  var = c(
    "info_treatment",
    "party_treatment",
    "leftright",
    "vote2017_green",
    "partyeval_6",
    "pint",
    "abi",
    "gender",
    "age"
  ),
  clean = c(
    "Information Treatment",
    "Party Cue Treatment",
    "Left-Right",
    "Vote for Greens in 2017",
    "Evaluation of SPD",
    "Political Interest",
    "Abitur",
    "Gender",
    "Age"
  )
)

fds <- left_join(fds,
                 clean_names)

ggplot(fds, aes(
  x = reorder(clean,
              med),
  y = med,
  ymin = lower,
  ymax = upper
)) +
  geom_hline(yintercept = 0, lty = 2) +
  geom_pointrange() +
  geom_text(aes(label = round(med, 2)),
            nudge_x = .3) +
  coord_flip() +
  theme_bw(base_size = 16) +
  xlab(NULL) +
  theme(panel.grid.major = element_blank(),
        panel.grid.minor = element_blank()) +
  ylab("First Difference\n(Third Quartile - First Quartile)") -> fdplot

fdplot

ggsave(file = "Figure3.pdf",
       width = 8,
       height = 6)
```

# Balance Tests

The following code creates the balance plots for the independent variables.

```{r,fig.width = 10, fig.height=5}
for (var in c("leftright",
              "vote2017_green",
              "partyeval_6",
              "pint",
              "abi",
              "gender",
              "age")) {
  df$dep <- df[[var]]
  
  balance <- lm(dep ~ maassen_treatment,
                data = df)
  
  visreg(balance,
         xvar = "maassen_treatment",
         plot = F)$fit -> plot_data
  
  var_clean <- case_when(
    var == "leftright" ~ "Left-Right",
    var == "vote2017_green" ~ "Vote for Greens in 2017",
    var == "partyeval_6" ~ "Evaluation of SPD",
    var == "pint" ~ "Political Interest",
    var == "abi" ~ "High Education",
    var == "gender" ~ "Gender",
    var == "age" ~ "Age"
  )
  
  ggplot(plot_data,
         aes(
           x = maassen_treatment,
           y = visregFit,
           ymin = visregLwr,
           ymax = visregUpr
         )) +
    geom_pointrange() +
    coord_flip() +
    xlab("Treatment Condition") +
    ylab(paste0("Average of ", var_clean)) +
    theme_bw() +
    theme(panel.grid.major = element_blank(),
          panel.grid.minor = element_blank()) -> bplot
  
  print(bplot)
  
  ggsave(bplot,
         file = paste0("FigureAppendix_", var, ".pdf"),
         width = 8,
         height = 4)
  
}
```

# Session Info

```{r}
pander(sessionInfo())
```
